package com.yqr.common.result;

import com.github.pagehelper.PageInfo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Collection;
import java.util.Optional;

/**
 * 统一响应结构
 *
 * @author simon
 * @date 2019/6/13 11:31
 */
@Data
@ApiModel("返回信息")
public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private static final String SUCCESS_MSG = "成功";
    private static final String FAIL_MSG = "失败";

    /**
     * 状态码
     *
     * @see ResultCode
     */
    @ApiModelProperty("状态码")
    private Integer code;

    @ApiModelProperty("提示信息")
    private String message;

    @ApiModelProperty("返回对象")
    private Response<T> data;

    @ApiModelProperty("是否成功")
    private Boolean success = true;

    private R(ResultCode resultCode) {
        this(resultCode, null, resultCode.getMessage());
    }

    private R(ResultCode resultCode, String msg) {
        this(resultCode, null, msg);
    }

    private R(ResultCode resultCode, T data) {
        this(resultCode, data, resultCode.getMessage());
    }

    private R(ResultCode resultCode, T data, String msg) {
        this(resultCode.getCode(), data, msg);
    }

    private R(int code, T data, String msg) {
        Response<T> response = new Response<>();
        response.setResponse(data);

        this.code = code;
        this.data = response;
        this.message = msg;
        this.success = ResultCode.OK.code == code;
    }

    /**
     * 判断返回是否为成功
     *
     * @param result Result
     * @return 是否成功
     */
    public static boolean isSuccess(@Nullable R<?> result) {
        return Optional.ofNullable(result)
                .map(x -> ObjectUtils.nullSafeEquals(ResultCode.OK.code, x.code))
                .orElse(Boolean.FALSE);
    }

    /**
     * 判断返回是否为成功
     *
     * @param result Result
     * @return 是否成功
     */
    public static boolean isNotSuccess(@Nullable R<?> result) {
        return !R.isSuccess(result);
    }

    /**
     * 返回R
     *
     * @param data 数据
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> data(T data) {
        return data(data, SUCCESS_MSG);
    }

    /**
     * 返回R
     *
     * @param data 数据
     * @param msg  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> data(T data, String msg) {
        return data(ResultCode.OK.code, data, msg);
    }

    /**
     * 构建带分页的响应，当pageInfo中不包含数据时，使用本方法。
     * 使用：
     * * R<PageInfoWrapper<User>> listUser(){
     * *   ...
     * *   return R.data(pageInfo,list)
     * * }
     *
     * @param pageInfo mapper查询出的分页信息
     * @param list     数据列表
     */
    public static <T, L extends Collection<T>> R<PageInfoWrapper<T>> data(PageInfo<T> pageInfo, L list) {
        return R.data(new PageInfoWrapper<>(pageInfo, list));
    }

    /**
     * 构建带分页的响应，当pageInfo中包含数据时，使用本方法。
     * 使用：
     * > R<PageInfoWrapper<User>> listUser(){
     * >   ...
     * >   Weekend<User> example=Weekend.of(User.class);
     * >   example.weekendCriteria()
     * >               .andEqualTo(User::getUsername, query.getUsername()+"%");
     * >   PageInfo<User> pageInfo = PageHelper.startPage(query.getPage(), query.getPageSize())
     * >               .doSelectPageInfo(() -> userManager.selectByExample(example));//当这里使用`doSelectPageInfo`时，返回的pageInfo中带有列表数据
     * >   return R.data(pageInfo);
     * > }
     *
     * @param pageInfo mapper查询出的带数据的分页信息
     */
    public static <T> R<PageInfoWrapper<T>> data(PageInfo<T> pageInfo) {
        return R.data(new PageInfoWrapper<>(pageInfo, pageInfo.getList()));
    }

    /**
     * 构建带分页的响应，当pageInfo中包含数据时，使用本方法。
     *
     * @param pageInfo mapper查询出的带数据的分页信息
     * @param message  消息
     */
    public static <T> R<PageInfoWrapper<T>> data(PageInfo<T> pageInfo, String message) {
        return R.data(new PageInfoWrapper<>(pageInfo, pageInfo.getList()))
                .message(message);
    }


    /**
     * 流式构建
     *
     * @param message 消息
     * @return 当前对象
     */
    public R<T> message(String message) {
        this.message = message;
        return this;
    }

    /**
     * 返回R
     *
     * @param code 状态码
     * @param data 数据
     * @param msg  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> data(int code, T data, String msg) {
        return new R<>(code, data, msg);
    }

    /**
     * 返回R
     *
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> success() {
        return new R<>(ResultCode.OK, SUCCESS_MSG);
    }

    /**
     * 返回R
     *
     * @param msg 消息
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> success(String msg) {
        return new R<>(ResultCode.OK, msg);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> success(ResultCode resultCode) {
        return new R<>(resultCode);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param msg        消息
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> success(ResultCode resultCode, String msg) {
        return new R<>(resultCode, msg);
    }

    /**
     * 返回R
     *
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> fail() {
        return new R<>(ResultCode.ERROR, FAIL_MSG);
    }


    /**
     * 返回R
     *
     * @param msg 消息
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(String msg) {
        return new R<>(ResultCode.ERROR, msg);
    }


    /**
     * 返回R
     *
     * @param code 状态码
     * @param msg  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(int code, String msg) {
        return new R<>(code, null, msg);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(ResultCode resultCode) {
        return new R<>(resultCode);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param msg        消息
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(ResultCode resultCode, String msg) {
        return new R<>(resultCode, msg);
    }

    /**
     * 返回R
     *
     * @param flag 成功状态
     * @return R
     */
    public static <T> R<T> status(boolean flag) {
        return flag ? success(SUCCESS_MSG) : fail(FAIL_MSG);
    }
}
